/*
 * Tezad - Classic puzzle game
 * Copyright 2009 Shayne Riley and Paul Maseberg
 *
 * Tezad is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Tezad is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Tezad.  If not, see <http://www.gnu.org/licenses/>
 * or write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * To contact the authors on questions or issues regarding the license,
 * you may send an email to <pezads at gmail dot com>
 */

#include "GameWell.h"


GameWell::GameWell(int inHeight, int inWidth, int inHiddenHeight)
: mHeight(inHeight), mWidth(inWidth), mHiddenHeight(inHiddenHeight)
{
    if (mHeight < 1)
    {
        throw std::out_of_range("height must be positive.");
    }
    if (mWidth < 1)
    {
        throw std::out_of_range("width must be positive.");
    }
    if (mHiddenHeight < 0 || mHiddenHeight > mHeight)
    {
        throw std::out_of_range(
                "hiddenHeight must be non-negative and less than height.");
    }

    // Everything is safe, now create the appropriate-sized empty well.
    mWell = new int[mHeight * mWidth];
    for (int i = 0; i < mHeight * mWidth; ++i) { mWell[i] = 0; }
}

GameWell::GameWell(const GameWell& src)
: mHeight(src.mHeight), mWidth(src.mWidth), mHiddenHeight(src.mHiddenHeight)
{
    // Create the well memory now, but deep copy from the source well.
    mWell = new int[mHeight * mWidth];
    for (int i = 0; i < mHeight * mWidth; ++i) { mWell[i] = src.mWell[i]; }
}

GameWell::~GameWell()
{
    delete [] mWell;
}

GameWell& GameWell::operator=(const GameWell& rhs)
{
    // Check self-assignment
    if (this == &rhs) { return (*this); }

    delete [] mWell;

    mHeight = rhs.mHeight;
    mWidth = rhs.mWidth;
    mHiddenHeight = rhs.mHiddenHeight;

    // Copy memory over.
    mWell = new int[mHeight * mWidth];
    for (int i = 0; i < mHeight * mWidth; ++i) { mWell[i] = rhs.mWell[i]; }

    return (*this);
}

int GameWell::width() const
{
    return mWidth;
}

int GameWell::height() const
{
    return mHeight;
}

int GameWell::visibleHeight() const
{
    return mHeight - mHiddenHeight;
}

int GameWell::brick(int row, int col) const
{
    if (row < 0 || row >= mHeight || col < 0 || col >= mWidth)
    {
        throw std::out_of_range("row and/or col are not in range.");
    }

    return mWell[row * mWidth + col];
}

void GameWell::setBrick(int row, int col, int inBrick)
{
    if (row < 0 || row >= mHeight || col < 0 || col >= mWidth)
    {
        throw std::out_of_range("row and/or col are not in range.");
    }

    mWell[row * mWidth + col] = inBrick;
}

void GameWell::clearRow(int row)
{
    if (row < 0 || row >= mHeight)
    {
        throw std::out_of_range("row is not in range.");
    }

    for (int shiftRow = row; shiftRow < mHeight - 1; ++shiftRow)
    {
        for (int col = 0; col < mWidth; ++col)
        {
            mWell[shiftRow * mWidth + col] = mWell[(shiftRow + 1) * mWidth + col];
        }
    }

    // Empty the top row.
    int topRow = mHeight - 1;
    for (int col = 0; col < mWidth; ++col)
    {
        mWell[topRow * mWidth + col] = 0;
    }
}
